const http = require("http")

/**
 * Layer
 * @param {*} path 
 * @param {*} handle 
 */
function Layer (path, handle) {
  if (! (this instanceof Layer) ) {
    return new Layer(path, handle)
  }
  this.path = path
  this.handle = handle
  return this
}

Layer.prototype.match = function (path) {
  return this.path == path
}

Layer.prototype.handle_request = function (req, res, next) {
  let fn = this.handle
  fn(req, res, next)
}

/**
 * Route
 * @param {} path 
 */
function Route (path) {
  this.path = path
  this.stack = []
  this.methods = {}
}

Route.prototype.dispatch = function (req, res, done) {
  console.log("dispatch")
  let stack = this.stack
  let i = 0
  function next() {
    let layer = stack[i++]
    if (!layer) {
      return done()
    }
    layer.handle_request(req, res, next)
  }
  next()
}

Route.prototype.get = function (handle) {
  var handles = Array.prototype.slice.call(arguments);
  for (var i = 0; i < handles.length; i++) {
    var handle = handles[i];
    if (typeof handle !== 'function') {
      var type = toString.call(handle);
      var msg = 'Route.' + 'get' + '() requires a callback function but got a ' + type
      throw new Error(msg);
    }

    var layer = Layer('/', handle);
    console.log(layer)
    layer.method = 'get';

    this.methods['get'] = true;
    this.stack.push(layer);
  }

  return this;
}


/**
 * Router
 */
function Router () {
  this.stack = []
}

Router.prototype.route = function (path, handle) {
  let route = new Route(path)
  let layer = new Layer(path, route.dispatch.bind(route))
  layer.route = route
  this.stack.push(layer)
  return route
}

Router.prototype.use = function (path, fn) {
  if (typeof path == 'function') {
    path = "/"
  }

  let layer = new Layer(path, fn)
  layer.route = undefined
  this.stack.push(layer)
}

Router.prototype.handle = function (req, res, out) {
  console.log("Router.handle start....")
  let i = 0
  let stack = this.stack  

  function next() {
    let layer = null
    let isMatch = false
    while (!isMatch && (layer=stack[i++])) {
      if (layer.match(req.url)) {
        isMatch = true
      }
    }

    if (layer) {
      layer.handle_request(req, res, next)
    } else {
      return out()
    }

  }

  next()

}




/**
 * express
 */
function express () {
  function app (req, res) {
    res.send = function (msg) {
      res.end(msg)
    }
    app.handle(req, res)
  }

  app.handle = function (req, res) {
    function out() {
      res.send("not found /")
    }
    this._router.handle(req, res, out)
  }

  app.lazyrouter = function () {
    if (!this._router) {
      this._router = new Router()
    }
  }

  app.get = function (path, handle) {
    if (handle) {
      this.lazyrouter()
      let route = this._router.route(path)
      route.get(handle)
    } else {
      return this.settings[path]
    }

  }

  app.use = function (path, fn) {
    if (!fn) {
      fn = path
      path = "/"
    }
    this.lazyrouter()
    // 非app
    if (!fn.handle) {
      return this._router.use(path, fn)
    }
  }

  app.listen = function (port) {
    http.createServer(app).listen(port)
  }

  return app
}

function main () {
  const app = express()


  app.use(function (req, res, next) {
    console.log("22222222222222222")
    next()
  })

  app.get("/", function (req, res) {
    res.send("OK")
  })

  app.listen(3000)
}

main()